home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 3: Developer Tools / Linux Cubed Series 3 - Developer Tools.iso / utils / file / managers / mc-3.2 / mc-3 / mc-3.2.1 / src / widget.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-05-17  |  40.9 KB  |  1,891 lines

  1. /* Widgets for the Midnight Commander
  2.  
  3.    Copyright (C) 1994, 1995 the Free Software Foundation
  4.    
  5.    Authors: 1994, 1995 Radek Doulik
  6.             1994, 1995 Miguel de Icaza
  7.             1995 Jakub Jelinek
  8.  
  9.    This program is free software; you can redistribute it and/or modify
  10.    it under the terms of the GNU General Public License as published by
  11.    the Free Software Foundation; either version 2 of the License, or
  12.    (at your option) any later version.
  13.  
  14.    This program is distributed in the hope that it will be useful,
  15.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  16.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17.    GNU General Public License for more details.
  18.  
  19.    You should have received a copy of the GNU General Public License
  20.    along with this program; if not, write to the Free Software
  21.    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  22.  
  23.  */
  24. /* "$Id: widget.c,v 1.3 1995/02/21 19:07:43 miguel Exp $" */
  25.  
  26. #include <config.h>
  27. #include <string.h>
  28. #include <stdio.h>
  29. #include <malloc.h>
  30. #include "tty.h"
  31. #include <ctype.h>
  32. #include "mad.h"
  33. #include "global.h"
  34. #include "util.h"
  35. #include "color.h"
  36. #include "mouse.h"
  37. #include "dlg.h"
  38. #include "widget.h"
  39. #include "win.h"
  40. #include "complete.h"
  41. #include "key.h"        /* XCTRL and ALT macros  */
  42.  
  43. #ifdef HAVE_X
  44. #   ifdef HAVE_XVIEW
  45. #       include "xvmain.h"
  46. #   else
  47. #       include "tkmain.h"
  48. #   endif
  49. #else
  50. #   define x_create_button(a,b,c)  1
  51. #   define x_create_radio(a,b,c)   1
  52. #   define x_create_check(a,b,c)   1
  53. #   define x_create_label(a,b,c)   1
  54. #   define x_create_input(a,b,c)   1
  55. #   define x_create_listbox(a,b,c) 1
  56. #   define x_create_buttonbar(a,b,c) 1
  57. #   define x_create_gauge(a,b,c) 1
  58. #   define x_listbox_select_nth(a,b)
  59. #   define x_list_insert(a,b,c)
  60. #   define x_redefine_label(a,b)
  61. #endif
  62.  
  63. #ifndef HAVE_TK
  64. #   define x_destroy_cmd(w)
  65. #endif
  66.  
  67. static int button_event (Gpm_Event *event, WButton *b);
  68.  
  69. int quote = 0;
  70.  
  71. static int button_callback (Dlg_head *h, WButton *b, int Msg, int Par)
  72. {
  73.     int stop = 0;
  74.  
  75.     switch (Msg){
  76.     case WIDGET_INIT:
  77.     return x_create_button (h, h->wdata, b);
  78.  
  79.     case WIDGET_HOTKEY:
  80.         if (b->hotkey == Par ||
  81.         (b->hotkey >= 'a' && b->hotkey <= 'z' && b->hotkey-32 == Par)){
  82.         button_callback (h, b, WIDGET_KEY, ' '); /* to make action */
  83.         return 1;
  84.     } else
  85.         return 0;
  86.     
  87.     case WIDGET_KEY:
  88.     if (Par != ' ' && Par != '\n')
  89.         break;
  90.  
  91.     if (b->callback)
  92.         stop = (*b->callback)(b->action, b->callback_data);
  93.     if (!b->callback || stop){
  94.         h->running = 0;
  95.         h->ret_value = b->action;
  96.     }
  97.     return 1;
  98.  
  99. #ifndef HAVE_X
  100.     case WIDGET_CURSOR:
  101.     widget_move (&b->widget, 0, b->hotpos);
  102.     return 1;
  103.  
  104.     case WIDGET_UNFOCUS:
  105.     case WIDGET_FOCUS:
  106.     case WIDGET_DRAW:
  107.     attrset ((Msg==WIDGET_FOCUS) ? FOCUSC : NORMALC);
  108.     widget_move (&b->widget, 0, 0);
  109.     addstr (b->text);
  110.  
  111.     if (b->hotpos >= 0){
  112.         attrset ((Msg ==  WIDGET_FOCUS) ? HOT_FOCUSC : HOT_NORMALC);
  113.         widget_move (&b->widget, 0, b->hotpos);
  114.         addch (b->text [b->hotpos]);
  115.         }
  116.     return 1;                                          
  117. #endif    
  118.     }    
  119.     return default_proc (h, Msg, Par);
  120. }
  121.  
  122. static int button_event (Gpm_Event *event, WButton *b)
  123. {
  124.     if (event->type & (GPM_DOWN|GPM_UP)){
  125.         Dlg_head *h=b->widget.parent;
  126.     dlg_select_widget (h, b);
  127.     if (event->type & GPM_UP){
  128.         button_callback (h, b, WIDGET_KEY, ' ');
  129.         (*h->callback) (h, ' ', DLG_POST_KEY);
  130.         return MOU_NORMAL;
  131.     }
  132.     }
  133.     return MOU_NORMAL;
  134. }
  135.  
  136. static void button_destroy (WButton *b)
  137. {
  138.     x_destroy_cmd (b);
  139.     free (b->text);
  140. }
  141.  
  142. WButton *button_new (int y, int x, int action, char *text, int hkey, int hpos,
  143.              int (*callback)(int, void *), void *callback_data)
  144. {
  145.     WButton *b = xmalloc (sizeof (WButton), "new_button");
  146.  
  147.     if (hkey>='A' && hkey<='Z')
  148.     hkey |= 0x20;
  149.  
  150.     init_widget (&b->widget, y, x, 1, strlen (text),
  151.          (callback_fn) button_callback,
  152.          (destroy_fn) button_destroy, (mouse_h)button_event);
  153.     b->action = action;
  154.     b->selected = 0;
  155.     b->text   = strdup (text);
  156.     b->hotkey = hkey;
  157.     b->hotpos = hpos;
  158.     b->callback = callback;
  159.     b->callback_data = callback_data;
  160.     widget_want_hotkey (b->widget, 1);
  161.     
  162.     return b;
  163. }
  164.  
  165. void button_set_text (WButton *b, char *text)
  166. {
  167.     free (b->text);
  168.     b->text = strdup (text);
  169. #ifdef HAVE_X
  170.     x_button_set (b, text);
  171. #else
  172.     button_callback (b->widget.parent, b, WIDGET_DRAW, 0);
  173.     refresh ();
  174. #endif
  175. }
  176.  
  177.  
  178. /* Radio button widget */
  179. static int radio_event (Gpm_Event *event, WRadio *r);
  180.  
  181. static int radio_callback (Dlg_head *h, WRadio *r, int Msg, int Par)
  182. {
  183.     int i;
  184.     
  185.     switch (Msg) {
  186.     case WIDGET_INIT:
  187.     return x_create_radio (h, h->wdata, r);
  188.     
  189. #ifndef HAVE_XVIEW
  190.     case WIDGET_HOTKEY:
  191.     if (r->upper_letter_is_hotkey){
  192.         int  i;
  193.         char *s;
  194.         
  195.         for (i = 0; i < r->count; i++){
  196.         for (s = r->texts [i]; *s; s++){
  197.             if (!(*s >= 'A' && *s <= 'Z' && (0x20|*s) == (0x20|Par)))
  198.             continue;
  199.             r->pos = i;
  200.             radio_callback (h, r, WIDGET_KEY, ' '); /* Take action */
  201.             return 1;
  202.         }
  203.         }
  204.     }
  205.     return 0;
  206.     
  207.     case WIDGET_KEY:
  208.     switch (Par){
  209.     case ' ':
  210.         r->sel = r->pos;
  211.             (*h->callback) (h, h->current->dlg_id, DLG_ACTION);
  212.         radio_callback (h, r, WIDGET_FOCUS, ' ');
  213.         return 1;
  214.  
  215.     case KEY_UP:
  216.     case KEY_LEFT:
  217.         if (r->pos > 0){
  218.         r->pos--;
  219.         return 1;
  220.         }
  221.         return 0;
  222.         
  223.     case KEY_DOWN:
  224.     case KEY_RIGHT:
  225.         if (r->count - 1 > r->pos) {
  226.         r->pos++;
  227.         return 1;
  228.         }
  229.     }
  230.     return 0;
  231.     
  232. #ifdef HAVE_TK
  233.     /* We manage a group of widgets, while Tk manages independent
  234.      * ones, so we have to do the focusing manually
  235.      */
  236.     case WIDGET_FOCUS:
  237.     case WIDGET_CURSOR:
  238.     tk_evalf ("focus %s.%d", (char *)(r->widget.wdata)+1, r->pos);
  239.     /* Do not call default_proc: we did the tk focus command */
  240.     return 1;
  241.  
  242. #endif
  243. #endif
  244.     
  245. #ifndef HAVE_X
  246.     case WIDGET_CURSOR:
  247.     (*h->callback) (h, h->current->dlg_id, DLG_ACTION);
  248.     radio_callback (h, r, WIDGET_FOCUS, ' ');
  249.     widget_move (&r->widget, r->pos, 1);
  250.     break;
  251.         
  252.     case WIDGET_UNFOCUS:
  253.     case WIDGET_FOCUS:
  254.     case WIDGET_DRAW:
  255.     for (i = 0; i < r->count; i++){
  256.         attrset ((i==r->pos && Msg==WIDGET_FOCUS) ? FOCUSC :NORMALC);
  257.         widget_move (&r->widget, i, 0);
  258.         printw ("(%c) %s", (r->sel == i) ? '*' : ' ', r->texts[i]);
  259.  
  260.         /* Draw the hotkey */
  261.         if (r->upper_letter_is_hotkey){
  262.         char *t = r->texts [i];
  263.  
  264.         while (*t && !(*t >= 'A' && *t <= 'Z'))
  265.             t++;
  266.         if (*t){
  267.             widget_move (&r->widget, i, 4+t - r->texts [i]);
  268.             attrset ((i==r->pos && Msg==WIDGET_FOCUS)
  269.                  ? HOT_FOCUSC :HOT_NORMALC);
  270.             addch (*t);
  271.         }
  272.         }
  273.     }
  274.     return 1;
  275.     break;
  276. #endif    
  277.     }
  278.     return default_proc (h, Msg, Par);
  279. }
  280.  
  281. #ifdef HAVE_TK
  282.     static void Radio_destroy (WRadio *r)
  283.     {
  284.     x_destroy_cmd (r);
  285.     }
  286. #   define radio_destroy (destroy_fn) Radio_destroy
  287. #else
  288. #   define radio_destroy 0
  289. #endif
  290.  
  291. static int radio_event (Gpm_Event *event, WRadio *r)
  292. {
  293.     if (event->type & (GPM_DOWN|GPM_UP)){
  294.         Dlg_head *h = r->widget.parent;
  295.     
  296.     r->pos = event->y - 1;
  297.     dlg_select_widget (h, r);
  298.     if (event->type & GPM_UP){
  299.         radio_callback (h, r, WIDGET_KEY, ' ');
  300.         radio_callback (h, r, WIDGET_FOCUS, 0);
  301.         (*h->callback) (h, ' ', DLG_POST_KEY);
  302.         return MOU_NORMAL;
  303.     }
  304.     }
  305.     return MOU_NORMAL;
  306. }
  307.  
  308. WRadio *radio_new (int y, int x, int count, char **texts, int use_hotkey)
  309. {
  310.     WRadio *r = xmalloc (sizeof (WRadio), "radio_new");
  311.     int i, max, m;
  312.  
  313.     /* Compute the longest string */
  314.     max = 0;
  315.     for (i = 0; i < count; i++){
  316.     m = strlen (texts [i]);
  317.     if (m > max)
  318.         max = m;
  319.     }
  320.  
  321.     init_widget (&r->widget, y, x, count, max, (callback_fn) radio_callback,
  322.          radio_destroy, (mouse_h) radio_event);
  323.     r->state = 1;
  324.     r->pos = 0;
  325.     r->sel = 0;
  326.     r->count = count;
  327.     r->texts = texts;
  328.     r->upper_letter_is_hotkey = use_hotkey;
  329.     widget_want_hotkey (r->widget, 1);
  330.     
  331.     return r;
  332. }
  333.  
  334.  
  335. /* Checkbutton widget */
  336.  
  337. static int check_event (Gpm_Event *event, WCheck *b);
  338.  
  339. static int check_callback (Dlg_head *h, WCheck *c, int Msg, int Par)
  340. {
  341.     switch (Msg) {
  342.     case WIDGET_INIT:
  343.     return x_create_check (h, h->wdata, c);
  344.  
  345.     case WIDGET_HOTKEY:
  346.         if (c->hotkey==Par ||
  347.         (c->hotkey>='a' && c->hotkey<='z' && c->hotkey-32==Par)){
  348.         check_callback (h, c, WIDGET_KEY, ' ');        /* make action */
  349.         return 1;
  350.     } else
  351.         return 0;
  352.  
  353.     case WIDGET_KEY:
  354.     if (Par != ' ')
  355.         break;
  356.     c->state ^= C_BOOL;
  357.     c->state ^= C_CHANGE;
  358.         (*h->callback) (h, h->current->dlg_id, DLG_ACTION);
  359.     check_callback (h, c, WIDGET_FOCUS, ' ');
  360.     return 1;
  361.  
  362. #ifndef HAVE_X    
  363.     case WIDGET_CURSOR:
  364.     widget_move (&c->widget, 0, 1);
  365.     break;
  366.     
  367.     case WIDGET_FOCUS:
  368.     case WIDGET_UNFOCUS:    
  369.     case WIDGET_DRAW:
  370.     attrset ((Msg == WIDGET_FOCUS) ? FOCUSC : NORMALC);
  371.     widget_move (&c->widget, 0, 0);
  372.     printw ("[%c] %s", (c->state & C_BOOL) ? 'x' : ' ', c->text);
  373.  
  374.     if (c->hotpos >= 0){
  375.         attrset ((Msg == WIDGET_FOCUS) ? HOT_FOCUSC : HOT_NORMALC);
  376.         widget_move (&c->widget, 0, + c->hotpos+4);
  377.         addch (c->text [c->hotpos]);
  378.     }
  379.     return 1;
  380. #endif    
  381.     }
  382.     return default_proc (h, Msg, Par);
  383. }
  384.  
  385. static int check_event (Gpm_Event *event, WCheck *c)
  386. {
  387.     if (event->type & (GPM_DOWN|GPM_UP)){
  388.         Dlg_head *h = c->widget.parent;
  389.     
  390.     dlg_select_widget (h, c);
  391.     if (event->type & GPM_UP){
  392.         check_callback (h, c, WIDGET_KEY, ' ');
  393.         check_callback (h, c, WIDGET_FOCUS, 0);
  394.         (*h->callback) (h, ' ', DLG_POST_KEY);
  395.         return MOU_NORMAL;
  396.     }
  397.     }
  398.     return MOU_NORMAL;
  399. }
  400.  
  401. #ifdef HAVE_TK
  402.     static void Check_destroy (WCheck *c)
  403.     {
  404.     x_destroy_cmd (c);
  405.     }
  406. #   define check_destroy (destroy_fn) Check_destroy
  407. #else
  408. #   define check_destroy 0
  409. #endif
  410.  
  411. WCheck *check_new (int y, int x, int state, char *text, int hkey, int hpos)
  412. {
  413.     WCheck *c =  xmalloc (sizeof (WRadio), "check_new");
  414.  
  415.     if (hkey >= 'A' && hkey <= 'Z')
  416.     hkey |= 0x20;
  417.  
  418.     init_widget (&c->widget, y, x, 1, strlen (text),
  419.          (callback_fn)check_callback,
  420.          check_destroy, (mouse_h) check_event);
  421.     c->state = state ? C_BOOL : 0;
  422.     c->text = text;
  423.     c->hotkey = hkey;
  424.     c->hotpos = hpos;
  425.     widget_want_hotkey (c->widget, 1);
  426.     
  427.     return c;
  428. }
  429.  
  430.  
  431. /* Label widget */
  432.  
  433. static int label_callback (Dlg_head *h, WLabel *l, int Msg, int Par)
  434. {
  435.     if (Msg == WIDGET_INIT)
  436.     return x_create_label (h, h->wdata, l);
  437.     
  438.     /* We don't want to get the focus */
  439.     if (Msg == WIDGET_FOCUS)
  440.     return 0;
  441. #ifndef HAVE_X
  442.     if (Msg == WIDGET_DRAW && l->text){
  443.     char *p = l->text, *q, c = 0;
  444.     int y = 0;
  445.     if (l->transparent)
  446.         attrset (DEFAULT_COLOR);
  447.     else
  448.         attrset (NORMALC);
  449.     for (;;){
  450.         int xlen;
  451.         
  452.         q = strchr (p, '\n');
  453.         if (q){
  454.         c = *q;
  455.         *q = 0;
  456.         }
  457.         widget_move (&l->widget, y, 0);
  458.         printw ("%s", p);
  459.         xlen = l->widget.cols - strlen (p);
  460.         if (xlen > 0)
  461.         printw ("%*s", xlen, " ");
  462.         if (!q)
  463.         break;
  464.         *q = c;
  465.         p = q + 1;
  466.         y++;
  467.     }
  468.     return 1;
  469.     }
  470. #endif    
  471.     return default_proc (h, Msg, Par);
  472. }
  473.  
  474. void label_set_text (WLabel *label, char *text)
  475. {
  476.     int newcols = label->widget.cols;
  477.     
  478.     if (label->text && text && !strcmp (label->text, text))
  479.         return; /* Flickering is not nice */
  480.  
  481.     if (label->text){
  482.     free (label->text);
  483.     }
  484.     if (text){
  485.     label->text = strdup (text);
  486.     if (label->auto_adjust_cols) {
  487.         newcols = strlen (text);
  488.         if (newcols > label->widget.cols)
  489.         label->widget.cols = newcols;
  490.     }
  491.     } else
  492.     label->text = 0;
  493.     
  494.     if (label->widget.parent)
  495. #ifdef HAVE_X
  496.     x_label_set_text (label, text);
  497. #else
  498.     label_callback (label->widget.parent, label, WIDGET_DRAW, 0);
  499. #endif
  500.     if (newcols < label->widget.cols)
  501.         label->widget.cols = newcols;
  502. }
  503.  
  504. static void label_destroy (WLabel *l)
  505. {
  506.     x_destroy_cmd (l);
  507.     if (l->text)
  508.     free (l->text);
  509. }
  510.  
  511. WLabel *label_new (int y, int x, char *text)
  512. {
  513.     WLabel *l = xmalloc (sizeof (WLabel), "label_new");
  514.  
  515.     init_widget (&l->widget, y, x, 1, 1,
  516.          (callback_fn) label_callback,
  517.          (destroy_fn) label_destroy, NULL);
  518.     l->text = text ? strdup (text) : 0;
  519.     l->auto_adjust_cols = 1;
  520.     l->transparent = 0;
  521.     widget_want_cursor (l->widget, 0);
  522.     return l;
  523. }
  524.  
  525.  
  526. /* Gauge widget (progress indicator) */
  527. /* Currently width is hardcoded here for text mode */
  528. #define gauge_len 47
  529.  
  530. static int gauge_callback (Dlg_head *h, WGauge *g, int Msg, int Par)
  531. {
  532.  
  533.     if (Msg == WIDGET_INIT)
  534.     return x_create_gauge (h, h->wdata, g);
  535.     
  536.     /* We don't want to get the focus */
  537.     if (Msg == WIDGET_FOCUS)
  538.     return 0;
  539.  
  540. #ifndef HAVE_X
  541.     if (Msg == WIDGET_DRAW){
  542.     widget_move (&g->widget, 0, 0);
  543.     attrset (NORMALC);
  544.     if (!g->shown)
  545.         printw ("%*s", gauge_len, "");
  546.     else {
  547.         long percentage, columns;
  548.         long total = g->max, done = g->current;
  549.         
  550.         if (total <= 0 || done < 0) {
  551.             done = 0;
  552.             total = 100;
  553.         }
  554.         if (done > total)
  555.             done = total;
  556.         while (total > 65535) {
  557.             total /= 256;
  558.             done /= 256;
  559.         }
  560.         percentage = (200 * done / total + 1) / 2;
  561.         columns = (2 * (gauge_len - 7) * done / total + 1) / 2;
  562.         addch ('[');
  563.         attrset (GAUGE_COLOR);
  564.         printw ("%*s", columns, "");
  565.         attrset (NORMALC);
  566.         printw ("%*s] %3d%%", gauge_len - 7 - columns, "", percentage);
  567.     }
  568.     return 1;
  569.     }
  570. #endif    
  571.     return default_proc (h, Msg, Par);
  572. }
  573.  
  574. void gauge_set_value (WGauge *g, int max, int current)
  575. {
  576.     if (g->current == current && g->max == max)
  577.         return; /* Do not flicker */
  578.     if (max == 0)
  579.         max = 1; /* I do not like division by zero :) */
  580. #ifdef HAVE_X
  581. /* NOTE: x_gauge_set_value has to be called before we change actual 
  582.  *       max and current values in g, since it assumes g->max and
  583.  *       g->current as the previous values and max and current
  584.  *       as the new ones :) */
  585.     x_gauge_set_value (g, max, current);
  586. #endif    
  587.     g->current = current;
  588.     g->max = max;
  589. #ifndef HAVE_X
  590.     gauge_callback (g->widget.parent, g, WIDGET_DRAW, 0);
  591. #endif
  592. }
  593.  
  594. void gauge_show (WGauge *g, int shown)
  595. {
  596.     if (g->shown == shown)
  597.         return;
  598.     g->shown = shown;
  599. #ifdef HAVE_X
  600.     x_gauge_show (g);
  601. #else
  602.     gauge_callback (g->widget.parent, g, WIDGET_DRAW, 0);
  603. #endif    
  604. }
  605.  
  606. static void gauge_destroy (WGauge *g)
  607. {
  608. }
  609.  
  610. WGauge *gauge_new (int y, int x, int shown, int max, int current)
  611. {
  612.     WGauge *g = xmalloc (sizeof (WGauge), "gauge_new");
  613.  
  614.     init_widget (&g->widget, y, x, 1, gauge_len,
  615.          (callback_fn) gauge_callback,
  616.          (destroy_fn) gauge_destroy, NULL);
  617.     g->shown = shown;
  618.     if (max == 0)
  619.         max = 1; /* I do not like division by zero :) */
  620.     g->max = max;
  621.     g->current = current;
  622.     g->pixels = 0;
  623.     widget_want_cursor (g->widget, 0);
  624.     return g;
  625. }
  626.  
  627.  
  628. /* Input widget */
  629.  
  630. /* Input widgets now have a global kill ring */
  631. /* Pointer to killed data */
  632. static char *kill_buffer = 0;
  633.  
  634. void update_input (WInput *in)
  635. {
  636. #ifndef HAVE_XVIEW
  637.     int    i, j;
  638.     char   c;
  639.     int    buf_len = strlen (in->buffer);
  640.  
  641.     if (in->disable_update)
  642.     return;
  643.  
  644.     /* Make the point visible */
  645.     if ((in->point < in->first_shown) ||
  646.     (in->point >= in->first_shown+in->field_len)){
  647.     in->first_shown = in->point - (in->field_len / 3);
  648.     if (in->first_shown < 0)
  649.         in->first_shown = 0;
  650.     }
  651.  
  652.     /* Adjust the mark */
  653.     if (in->mark > buf_len)
  654.     in->mark = buf_len;
  655. #ifdef HAVE_X
  656.     tk_update_input (in);
  657. #else
  658.     attrset (in->color);
  659.     
  660.     widget_move (&in->widget, 0, 0);
  661.     for (i = 0; i < in->field_len; i++)
  662.     addch (' ');
  663.     widget_move (&in->widget, 0, 0);
  664.     
  665.     for (i = 0, j = in->first_shown; i < in->field_len && in->buffer [j]; i++){
  666.     c = in->buffer [j++];
  667.     c = is_printable (c) ? c : '.';
  668.     if (in->is_password)
  669.         c = '*';
  670.     addch (c);
  671.     }
  672.     widget_move (&in->widget, 0, in->point - in->first_shown);
  673. #endif
  674.     
  675.     in->first = 0;
  676. #endif
  677. }
  678.  
  679. void winput_set_origin (WInput *in, int x, int field_len)
  680. {
  681.     in->widget.x    = x;
  682.     in->field_len = in->widget.cols = field_len;
  683.     update_input (in);
  684. }
  685.  
  686. static void input_destroy (WInput *in)
  687. {
  688.     if (!in){
  689.     fprintf (stderr, "Internal error: null Input *\n");
  690.     exit (1);
  691.     }
  692.  
  693.     if (in->history){
  694.     Hist *current, *old;
  695.  
  696.     current = in->history;
  697.     while (current->next)
  698.         current = current->next;
  699.     while (current){
  700.         old = current;
  701.         current = current->prev;
  702.         free (old->text);
  703.         free (old);
  704.     }
  705.     }
  706.     x_destroy_cmd (in);
  707.     free (in->buffer);
  708.     free_completions (in);
  709. }
  710.  
  711. static char disable_update = 0;
  712.  
  713. void input_disable_update (WInput *in)
  714. {
  715.     in->disable_update++;
  716. }
  717.  
  718. void input_enable_update (WInput *in)
  719. {
  720.     in->disable_update--;
  721.     update_input (in);
  722. }
  723.  
  724. int push_history (WInput *in, char *text)
  725. {
  726.     Hist *new;
  727.     char *p;
  728.     
  729.     for (p = text; *p == ' ' || *p == '\t'; p++);
  730.     if (!*p)
  731.         return 0;
  732.     if (in->history){
  733.     while (in->history->next)
  734.         in->history = in->history->next;
  735.     if (!strcmp (in->history->text, text))
  736.         return 1;
  737.         new = xmalloc (sizeof (Hist), "push_history");
  738.     in->history->next = new;
  739.     } else
  740.         new = xmalloc (sizeof (Hist), "push_history");
  741.     in->need_push = 0;
  742.     new->next = 0;
  743.     new->prev = in->history;
  744.     new->text = strdup (text);
  745.     in->history = new;
  746.     return 2;
  747. }
  748.  
  749. /* Cleans the input line and adds the current text to the history */
  750. void new_input (WInput *in)
  751. {
  752.     if (in->buffer)
  753.     push_history (in, in->buffer);
  754.     in->need_push = 1;
  755.     in->buffer [0] = 0;
  756.     in->point = 0;
  757.     in->mark = 0;
  758.     free_completions (in);
  759.     update_input (in);
  760. }
  761.  
  762. static int insert_char (WInput *in, int c_code)
  763. {
  764.     int i;
  765.  
  766.     if (c_code == -1)
  767.     return 0;
  768.     
  769.     in->need_push = 1;
  770.     if (strlen (in->buffer)+1 == in->current_max_len){
  771.     /* Expand the buffer */
  772.     char *narea = realloc(in->buffer, in->current_max_len + in->field_len);
  773.     if (narea){
  774.         in->buffer = narea;
  775.         in->current_max_len += in->field_len;
  776.     }
  777.     }
  778.     if (strlen (in->buffer)+1 < in->current_max_len){
  779.     int l = strlen (&in->buffer [in->point]);
  780.     for (i = l+2; i > 0; i--)
  781.         in->buffer [in->point+i] = in->buffer [in->point+i-1];
  782.     in->buffer [in->point] = c_code;
  783.     in->point++;
  784.     }
  785.     return 1;
  786. }
  787.  
  788. static void beginning_of_line (WInput *in)
  789. {
  790.     in->point = 0;
  791. }
  792.  
  793. static void end_of_line (WInput *in)
  794. {
  795.     in->point = strlen (in->buffer);
  796. }
  797.  
  798. static void backward_char (WInput *in)
  799. {
  800.     if (in->point)
  801.     in->point--;
  802. }
  803.  
  804. static void forward_char (WInput *in)
  805. {
  806.     if (in->buffer [in->point])
  807.     in->point++;
  808. }
  809.  
  810. static void forward_word (WInput *in)
  811. {
  812.     char *p = in->buffer+in->point;
  813.  
  814.     while ((*p && isspace (*p)) || ispunct (*p))
  815.     p++;
  816.     while (*p && isalnum (*p))
  817.     p++;
  818.     in->point = p - in->buffer;
  819. }
  820.  
  821. static void backward_word (WInput *in)
  822. {
  823.     char *p = in->buffer+in->point;
  824.  
  825.     while (p-1 > in->buffer-1 && (isspace (*(p-1)) || ispunct (*(p-1))))
  826.     p--;
  827.     while (p-1 > in->buffer-1 && isalnum (*(p-1)))
  828.     p--;
  829.     in->point = p - in->buffer;
  830. }
  831.  
  832. static void backward_delete (WInput *in)
  833. {
  834.     int i;
  835.     
  836.     if (!in->point)
  837.     return;
  838.     for (i = in->point; in->buffer [i-1]; i++)
  839.     in->buffer [i-1] = in->buffer [i];
  840.     in->need_push = 1;
  841.     in->point--;
  842. }
  843.  
  844. static void delete_char (WInput *in)
  845. {
  846.     int i;
  847.  
  848.     for (i = in->point; in->buffer [i]; i++)
  849.     in->buffer [i] = in->buffer [i+1];
  850.     in->need_push = 1;
  851. }
  852.  
  853. static void copy_region (WInput *in, int x_first, int x_last)
  854. {
  855.     int first = min (x_first, x_last);
  856.     int last  = max (x_first, x_last);
  857.     
  858.     if (last == first)
  859.     return;
  860.     
  861.     if (kill_buffer)
  862.     free (kill_buffer);
  863.     
  864.     kill_buffer = xmalloc (last-first + 1, "copy_region");
  865.     strncpy (kill_buffer, in->buffer+first, last-first);
  866.     kill_buffer [last-first] = 0;
  867. }
  868.  
  869. static void delete_region (WInput *in, int x_first, int x_last)
  870. {
  871.    int first = min (x_first, x_last);
  872.    int last  = max (x_first, x_last);
  873.  
  874.    in->point = first;
  875.    in->mark  = first;
  876.    strcpy (&in->buffer [first], &in->buffer [last]);
  877.    in->need_push = 1;
  878. }
  879.  
  880. static void kill_word (WInput *in)
  881. {
  882.     int old_point = in->point;
  883.     int new_point;
  884.  
  885.     forward_word (in);
  886.     new_point = in->point;
  887.     in->point = old_point;
  888.  
  889.     copy_region (in, old_point, new_point);
  890.     delete_region (in, old_point, new_point);
  891.     in->need_push = 1;
  892. }
  893.  
  894. static void back_kill_word (WInput *in)
  895. {
  896.     int old_point = in->point;
  897.     int new_point;
  898.  
  899.     backward_word (in);
  900.     new_point = in->point;
  901.     in->point = old_point;
  902.  
  903.     copy_region (in, old_point, new_point);
  904.     delete_region (in, old_point, new_point);
  905.     in->need_push = 1;
  906. }
  907.  
  908. static void set_mark (WInput *in)
  909. {
  910.     in->mark = in->point;
  911. }
  912.  
  913. static void kill_save (WInput *in)
  914. {
  915.     copy_region (in, in->mark, in->point);
  916. }
  917.  
  918. static void kill_region (WInput *in)
  919. {
  920.     kill_save (in);
  921.     delete_region (in, in->point, in->mark);
  922. }
  923.  
  924. static void yank (WInput *in)
  925. {
  926.     char *p;
  927.     
  928.     if (!kill_buffer)
  929.         return;
  930.     for (p = kill_buffer; *p; p++)
  931.     insert_char (in, *p);
  932. }
  933.  
  934. static void kill_line (WInput *in)
  935. {
  936.     if (kill_buffer)
  937.     free (kill_buffer);
  938.     kill_buffer = strdup (&in->buffer [in->point]);
  939.     in->buffer [in->point] = 0;
  940. }
  941.  
  942. void assign_text (WInput *in, char *text)
  943. {
  944.     free_completions (in);
  945.     in->buffer = strdup (text);    /* was in->buffer->text */
  946.     in->current_max_len = strlen (in->buffer) + 1;
  947.     in->point = strlen (in->buffer);
  948.     in->mark = 0;
  949.     in->need_push = 1;
  950. }
  951.  
  952. static void hist_prev (WInput *in)
  953. {
  954.     if (!in->history)
  955.     return;
  956.  
  957.     if (in->need_push) {
  958.     switch (push_history (in, in->buffer)) {
  959.      case 2: in->history = in->history->prev; break;
  960.      case 1: if (in->history->prev) in->history = in->history->prev; break;
  961.      case 0: break;
  962.     }
  963.     } else if (in->history->prev)
  964.         in->history = in->history->prev;
  965.     else
  966.         return;
  967.     assign_text (in, in->history->text);
  968.     in->need_push = 0;
  969. }
  970.  
  971. static void hist_next (WInput *in)
  972. {
  973.     if (in->need_push) {
  974.         switch (push_history (in, in->buffer)) {
  975.          case 2:
  976.             assign_text (in, "");
  977.             return;
  978.          case 0:
  979.             return;
  980.         }
  981.     }
  982.     
  983.     if (!in->history)
  984.     return;
  985.  
  986.     if (!in->history->next) {
  987.         assign_text (in, "");
  988.     return;
  989.     }
  990.     
  991.     in->history = in->history->next;
  992.     assign_text (in, in->history->text);
  993.     in->need_push = 0;
  994. }
  995.  
  996. static struct {
  997.     int key_code;
  998.     void (*fn)(WInput *in);
  999. } input_map [] = {
  1000.     /* Motion */
  1001.     { XCTRL('a'),   beginning_of_line },
  1002.     { KEY_HOME,      beginning_of_line },
  1003.     { KEY_A1,      beginning_of_line },
  1004.     { XCTRL('e'),   end_of_line },
  1005.     { KEY_END,         end_of_line },
  1006.     { KEY_C1,         end_of_line },
  1007.     { KEY_LEFT,     backward_char },
  1008.     { XCTRL('b'),   backward_char },
  1009.     { ALT('b'),     backward_word },
  1010.     { KEY_RIGHT,    forward_char },
  1011.     { XCTRL('f'),   forward_char },
  1012.     { ALT('f'),     forward_word },
  1013.  
  1014.     /* Editing */
  1015.     { 0177,         backward_delete },
  1016.     { KEY_BACKSPACE,backward_delete },
  1017.     { XCTRL('h'),   backward_delete },
  1018.     { KEY_DC,       delete_char },
  1019.     { XCTRL('d'),   delete_char },
  1020.     { ALT('d'),     kill_word },
  1021.     { ALT(KEY_BACKSPACE), back_kill_word },
  1022.     { ALT(XCTRL('h')), back_kill_word },
  1023.     { ALT(127),     back_kill_word },
  1024.     
  1025.     /* Region manipulation */
  1026.     { 0,            set_mark },
  1027.     { XCTRL('w'),   kill_region },
  1028.     { ALT('w'),     kill_save },
  1029.     { XCTRL('y'),   yank },
  1030.     { XCTRL('k'),   kill_line },
  1031.     
  1032.     /* History */
  1033.     { ALT('p'),     hist_prev },
  1034.     { ALT('n'),     hist_next },
  1035.     
  1036.     /* Completion */
  1037.     { ALT('\t'),      complete },
  1038.     
  1039.     { 0,            0 }
  1040. };
  1041.  
  1042. /* This function is a test for a special input key used in complete.c */
  1043. /* Returns 0 if it is not a special key, 1 if it is a non-complete key
  1044.    and 2 if it is a complete key */
  1045. int is_in_input_map (WInput *in, int c_code)
  1046. {
  1047.     int i;
  1048.     
  1049.     for (i = 0; input_map [i].fn; i++)
  1050.     if (c_code == input_map [i].key_code)
  1051.         if (input_map [i].fn == complete)
  1052.             return 2;
  1053.         else
  1054.             return 1;
  1055.     return 0;
  1056. }
  1057.  
  1058. int handle_char (WInput *in, int c_code)
  1059. {
  1060.     int    i;
  1061.     int    v;
  1062.  
  1063.     v = 0;
  1064.  
  1065. #ifdef HAVE_TK    
  1066.     in->inserted_one = 0;
  1067. #endif
  1068.     if (quote){
  1069.         free_completions (in);
  1070.     v = insert_char (in, c_code);
  1071.     update_input (in);
  1072.     quote = 0;
  1073.     return v;
  1074.     }
  1075.  
  1076.     for (i = 0; input_map [i].fn; i++){
  1077.     if (c_code == input_map [i].key_code){
  1078.         if (input_map [i].fn != complete)
  1079.             free_completions (in);
  1080.         (*input_map [i].fn)(in);
  1081.         v = 1;
  1082.         break;
  1083.     }
  1084.     }
  1085.     if (!input_map [i].fn){
  1086.     if (c_code > 255 || !is_printable (c_code))
  1087.         return 0;
  1088.     if (in->first){
  1089.         *in->buffer = 0;
  1090.         in->point = 0;
  1091.     }
  1092.         free_completions (in);
  1093.     v = insert_char (in, c_code);
  1094.     in->inserted_one = c_code;
  1095.     }
  1096.     if (!disable_update)
  1097.     update_input (in);
  1098.     return v;
  1099. }
  1100.  
  1101. /* Inserts text in input line */
  1102. void stuff (WInput *in, char *text, int insert_extra_space)
  1103. {
  1104.     input_disable_update (in);
  1105.     while (*text)
  1106.     handle_char (in, *text++);
  1107.     if (insert_extra_space)
  1108.     handle_char (in, ' ');
  1109.     input_enable_update (in);
  1110.     update_input (in);
  1111. }
  1112.  
  1113. void input_set_point (WInput *in, int pos)
  1114. {
  1115.     if (pos > in->current_max_len)
  1116.     pos = in->current_max_len;
  1117.     if (pos != in->point)
  1118.         free_completions (in);
  1119.     in->point = pos;
  1120.     update_input (in);
  1121. }
  1122.  
  1123. int input_event (Gpm_Event *event, WInput *b);
  1124.  
  1125. static int input_callback (Dlg_head *h, WInput *in, int Msg, int Par)
  1126. {
  1127.     int    t;
  1128.  
  1129.     switch (Msg){
  1130.     case WIDGET_INIT:
  1131.     return x_create_input (h, h->wdata, in);
  1132.  
  1133. #ifndef HAVE_XVIEW
  1134.     case WIDGET_KEY:
  1135.     if (Par == XCTRL('q')){
  1136.         int v;
  1137.         
  1138.         quote = 1;
  1139.         v = handle_char (in, mi_getch ());
  1140.         quote = 0;
  1141.         return v;
  1142.     }
  1143.     if (Par == KEY_UP || Par == KEY_DOWN ||
  1144.         Par == ESC_CHAR || Par == KEY_F(10) ||
  1145.         Par == XCTRL('g'))
  1146.         return 0;        /* We don't handle up/down */
  1147.  
  1148.     if (Par == '\n'){
  1149.         dlg_one_down (h);
  1150.         return 1;
  1151.     }
  1152.     return handle_char (in, Par);
  1153.  
  1154.     case WIDGET_FOCUS:
  1155.     case WIDGET_UNFOCUS:    
  1156.     case WIDGET_DRAW:
  1157.     /* Very ugly hack */
  1158.     t = in->first;
  1159.     update_input (in);
  1160.     in->first = t;
  1161.     break;
  1162. #endif /* !HAVE_XVIEW */
  1163. #ifndef HAVE_X
  1164.     case WIDGET_CURSOR:
  1165.     widget_move (&in->widget, 0, in->point - in->first_shown);
  1166.     return 1;
  1167. #endif
  1168.     
  1169.     }
  1170.     return default_proc (h, Msg, Par);
  1171. }
  1172.  
  1173. /* Not declared static, since we check against this value in dlg.c */
  1174. /* FIXME: Declare static again and provide an identification mechanism */
  1175. int input_event (Gpm_Event *event, WInput *in)
  1176. {
  1177.     if (event->type & (GPM_DOWN|GPM_DRAG)){
  1178.     dlg_select_widget (in->widget.parent, in);
  1179.     
  1180.     in->point = strlen (in->buffer);
  1181.     if (event->x - in->first_shown - 1 < in->point)
  1182.         in->point = event->x - in->first_shown - 1;
  1183.     if (in->point < 0)
  1184.         in->point = 0;
  1185.  
  1186.     update_input (in);
  1187.     }
  1188.     return MOU_NORMAL;
  1189. }
  1190.  
  1191. WInput *input_new (int y, int x, int color, int len, char *def_text)
  1192. {
  1193.     WInput *in = xmalloc (sizeof (WInput), "input_new");
  1194.     int   initial_buffer_len;
  1195.  
  1196.     init_widget (&in->widget, y, x, 1, len,
  1197.          (callback_fn) input_callback,
  1198.          (destroy_fn) input_destroy, (mouse_h)input_event);
  1199.  
  1200.  
  1201.     initial_buffer_len = 1 + max (len, strlen (def_text));
  1202.     in->completions = NULL;
  1203.     in->completion_flags =
  1204.     INPUT_COMPLETE_FILENAMES | INPUT_COMPLETE_HOSTNAMES | 
  1205.         INPUT_COMPLETE_VARIABLES | INPUT_COMPLETE_USERNAMES;
  1206.     in->current_max_len = initial_buffer_len;
  1207.     in->buffer = xmalloc (initial_buffer_len, "create_input: in->buffer");
  1208.     in->color = color;
  1209.     in->field_len = len;
  1210.     in->first = 1;
  1211.     in->first_shown = 0;
  1212.     in->disable_update = 0;
  1213.     in->mark = 0;
  1214.     in->need_push = 1;
  1215.     in->is_password = 0;
  1216.  
  1217.     /* history setup */
  1218.     in->history = NULL;
  1219.     strcpy (in->buffer, def_text);
  1220.     in->point = strlen (in->buffer);
  1221.     in->first = 1;
  1222.     return in;
  1223. }
  1224.  
  1225.  
  1226. /* Listbox widget */
  1227.  
  1228. /* Should draw the scrollbar, but currently draws only
  1229.  * indications that there is more information
  1230.  */
  1231. static int listbox_cdiff (WLEntry *s, WLEntry *e);
  1232.  
  1233. static void listbox_drawscroll (WListbox *l)
  1234. {
  1235.     extern int slow_terminal;
  1236.     int line;
  1237.     int i, top;
  1238.     int max_line = l->height-1;
  1239.     
  1240.     /* Are we at the top? */
  1241.     widget_move (&l->widget, 0, l->width);
  1242.     if (l->list == l->top)
  1243.     one_vline ();
  1244.     else
  1245.     addch ('^');
  1246.  
  1247.     /* Are we at the bottom? */
  1248.     widget_move (&l->widget, max_line, l->width);
  1249.     top = listbox_cdiff (l->list, l->top);
  1250.     if ((top + l->height == l->count) || l->height >= l->count)
  1251.     one_vline ();
  1252.     else
  1253.     addch ('+');
  1254.  
  1255.     /* Now draw the nice relative pointer */
  1256.     if (l->count)
  1257.     line = 1+ ((l->pos * (l->height-2)) / l->count);
  1258.     else
  1259.     line = 0;
  1260.     
  1261.     for (i = 1; i < max_line; i++){
  1262.     widget_move (&l->widget, i, l->width);
  1263.     if (i != line)
  1264.         one_vline ();
  1265.     else
  1266.         addch ('*');
  1267.     }
  1268. }
  1269.     
  1270. static void listbox_draw (WListbox *l, Dlg_head *h, int focused)
  1271. {
  1272.     WLEntry *e;
  1273.     int i;
  1274.     int sel_line;
  1275.     int normalc, selc;
  1276.     char *text; 
  1277.  
  1278.     if (focused){
  1279.     normalc = NORMALC;
  1280.     selc    = FOCUSC;
  1281.     } else {
  1282.     normalc = NORMALC;
  1283.     selc    = HOT_FOCUSC;
  1284.     }
  1285.     sel_line = -1;
  1286.  
  1287.     for (e = l->top, i = 0; (i < l->height); i++){
  1288.     
  1289.     /* Display the entry */
  1290.     if (e == l->current && sel_line == -1){
  1291.         sel_line = i;
  1292.         attrset (selc);
  1293.     } else
  1294.         attrset (normalc);
  1295.  
  1296.     widget_move (&l->widget, i, 0);
  1297.  
  1298.     if ((i > 0 && e == l->list) || !l->list)
  1299.         text = "";
  1300.     else {
  1301.         text = e->text;
  1302.         e = e->next;
  1303.     }
  1304.     printw (" %-*s ", l->width-2, name_trunc (text, l->width-2));
  1305.     }
  1306.     l->cursor_y = sel_line;
  1307.     if (!l->scrollbar)
  1308.     return;
  1309.     attrset (normalc);
  1310.     listbox_drawscroll (l);
  1311. }
  1312.  
  1313. /* Returns the number of items between s and e,
  1314.    must be on the same linked list */
  1315. static int listbox_cdiff (WLEntry *s, WLEntry *e)
  1316. {
  1317.     int count;
  1318.  
  1319.     for (count = 0; s != e; count++)
  1320.     s = s->next;
  1321.     return count;
  1322. }
  1323.  
  1324. static WLEntry *listbox_check_hotkey (WListbox *l, int key)
  1325. {
  1326.     int i;
  1327.     WLEntry *e;
  1328.     
  1329.     i = 0;
  1330.     e = l->list;
  1331.     if (!e)
  1332.     return 0;
  1333.     
  1334.     while (1){
  1335.  
  1336.     /* If we didn't find anything, return */
  1337.     if (i && e == l->list)
  1338.         return 0;
  1339.  
  1340.     if (e->hotkey == key)
  1341.         return e;
  1342.     
  1343.     i++;
  1344.     e = e->next;
  1345.     }
  1346. }
  1347.  
  1348. /* Used only for display updating, for avoiding line at a time scroll */
  1349. void listbox_select_last (WListbox *l, int set_top)
  1350. {
  1351.     if (l->list){
  1352.     l->current = l->list->prev;
  1353.     l->pos = l->count - 1;
  1354.     if (set_top)
  1355.         l->top = l->list->prev;
  1356.     x_listbox_select_nth (l, l->pos);
  1357.     }
  1358. }
  1359.  
  1360. void listbox_remove_current (WListbox *l)
  1361. {
  1362.     WLEntry *p;
  1363.     
  1364.     /* Ok, note: this won't allow for emtpy lists */
  1365.     if (!l->count || l->count == 1)
  1366.     return;
  1367.     
  1368. #ifdef HAVE_X
  1369.     if (l->widget.wdata != (widget_data) NULL) {
  1370.         x_listbox_delete_nth (l, l->pos);
  1371.         if (l->current->next != l->list)
  1372.             x_listbox_select_nth (l, l->pos);
  1373.         else if (l->current != l->list)
  1374.             x_listbox_select_nth (l, 0);
  1375.     }
  1376. #endif
  1377.     l->count--;
  1378.     l->current->next->prev = l->current->prev;
  1379.     l->current->prev->next = l->current->next;
  1380.     p = l->current;
  1381.     if (p->next == l->list) {
  1382.     l->current = p->prev;
  1383.     l->pos--;
  1384.     }    
  1385.     else 
  1386.     l->current = p->next;
  1387.     
  1388.     if (p == l->list)
  1389.         l->list = l->top = p->next;
  1390.  
  1391.     free (p->text);
  1392.     free (p);
  1393. }
  1394.  
  1395. /* Makes *e the selected entry (sets current and pos) */
  1396. void listbox_select_entry (WListbox *l, WLEntry *dest)
  1397. {
  1398.     WLEntry *e;
  1399.     int pos;
  1400.     int top_seen;
  1401.     
  1402.     top_seen = 0;
  1403.     
  1404.     /* Special case */
  1405.     for (pos = 0, e = l->list; pos < l->count; e = e->next, pos++){
  1406.  
  1407.     if (e == l->top)
  1408.         top_seen = 1;
  1409.     
  1410.     if (e == dest){
  1411.         l->current = e;
  1412.         if (top_seen){
  1413.         while (listbox_cdiff (l->top, l->current) >= l->height)
  1414.             l->top = l->top->next;
  1415.         } else {
  1416.         l->top = l->current;
  1417.         }
  1418.         l->pos = pos;
  1419.         x_listbox_select_nth (l, l->pos);
  1420.         return;
  1421.     }
  1422.     }
  1423.     /* If we are unable to find it, set decent values */
  1424.     l->current = l->top = l->list;
  1425.     l->pos = 0;
  1426.     x_listbox_select_nth (l, l->pos);
  1427. }
  1428.  
  1429. /* Selects from base the pos element */
  1430. static WLEntry *listbox_select_pos (WListbox *l, WLEntry *base, int pos)
  1431. {
  1432.     WLEntry *last = l->list->prev;
  1433.  
  1434.     if (base == last)
  1435.         return last;
  1436.     while (pos--){
  1437.     base = base->next;
  1438.     if (base == last)
  1439.         break;
  1440.     }
  1441.     return base;
  1442. }
  1443.  
  1444. static inline int listbox_back (WListbox *l)
  1445. {
  1446.     if (l->pos){
  1447.     listbox_select_entry (l, listbox_select_pos (l, l->list, l->pos-1));
  1448.     return 1;
  1449.     }
  1450.     return 0;
  1451. }
  1452.  
  1453. static inline int listbox_fwd (WListbox *l)
  1454. {
  1455.     if (l->current != l->list->prev){
  1456.     listbox_select_entry (l, listbox_select_pos (l, l->list, l->pos+1));
  1457.     return 1;
  1458.     }
  1459.     return 0;
  1460. }
  1461.  
  1462. /* Returns 1 if we want a redraw */
  1463. static int listbox_key (WListbox *l, int key)
  1464. {
  1465.     int i;
  1466.     int j = 0;
  1467.     
  1468.     switch (key){
  1469.     case KEY_HOME:
  1470.     case KEY_A1:
  1471.     l->current = l->top = l->list;
  1472.     l->pos = 0;
  1473.     return 1;
  1474.     
  1475.     case KEY_END:
  1476.     case KEY_C1:
  1477.     l->current = l->top = l->list->prev;
  1478.     for (i = min (l->height - 1, l->count - 1); i; i--)
  1479.         l->top = l->top->prev;
  1480.     l->pos = l->count - 1;
  1481.     return 1;
  1482.     
  1483.     case XCTRL('p'):
  1484.     case KEY_UP:
  1485.     listbox_back (l);
  1486.     return 1;
  1487.     
  1488.     case XCTRL('n'):
  1489.     case KEY_DOWN:
  1490.     listbox_fwd (l);
  1491.     return 1;
  1492.  
  1493.     case KEY_NPAGE:
  1494.     case XCTRL('v'):
  1495.     for (i = 0; i < l->height-1; i++)
  1496.         j |= listbox_fwd (l);
  1497.     return j > 0;
  1498.     
  1499.     case KEY_PPAGE:
  1500.     case ALT('v'):
  1501.     for (i = 0; i < l->height-1; i++)
  1502.         j |= listbox_back (l);
  1503.     return j > 0;
  1504.     }
  1505.     return 0;
  1506. }
  1507.  
  1508. static int listbox_event (Gpm_Event *event, WListbox *l);
  1509. static int listbox_callback (Dlg_head *h, WListbox *l, int msg, int par)
  1510. {
  1511.     WLEntry  *e;
  1512.     /* int selected_color; Never used */
  1513.     int ret_code;
  1514.     
  1515.     switch (msg){
  1516.     case WIDGET_INIT:
  1517.     return x_create_listbox (h, h->wdata, l);
  1518.  
  1519.     case WIDGET_HOTKEY:
  1520.     if ((e = listbox_check_hotkey (l, par)) != NULL){
  1521.         listbox_select_entry (l, e);
  1522.  
  1523.         /* Take the appropriate action */
  1524.         if (l->action == listbox_finish){
  1525.         l->widget.parent->running   = 0;
  1526.         l->widget.parent->ret_value = B_ENTER;
  1527.         } else if (l->action == listbox_cback){
  1528.         if ((*l->cback)(l) == listbox_finish){
  1529.             l->widget.parent->running = 0;
  1530.             l->widget.parent->ret_value = B_ENTER;
  1531.         }
  1532.         }
  1533.         return 1;
  1534.     } else
  1535.         return 0;
  1536.     
  1537.     case WIDGET_KEY:
  1538.     if ((ret_code = listbox_key (l, par)))
  1539.         listbox_draw (l, h, 1);
  1540.     return ret_code;
  1541.  
  1542. #ifndef HAVE_X
  1543.     case WIDGET_CURSOR:
  1544.     widget_move (&l->widget, l->cursor_y, 0);
  1545.     return 1;
  1546.     
  1547.     case WIDGET_FOCUS:
  1548.     case WIDGET_UNFOCUS:
  1549.     case WIDGET_DRAW:
  1550.     listbox_draw (l, h, msg != WIDGET_UNFOCUS);
  1551.     return 1;
  1552. #endif    
  1553.     }
  1554.     return default_proc (h, msg, par);
  1555. }
  1556.  
  1557. static int listbox_event (Gpm_Event *event, WListbox *l)
  1558. {
  1559. #ifndef HAVE_X
  1560.     int i;
  1561.     
  1562.     Dlg_head *h = l->widget.parent;
  1563.     
  1564.     /* Single click */
  1565.     if (event->type & GPM_DOWN)
  1566.     dlg_select_widget (l->widget.parent, l);
  1567.     if (event->type & (GPM_DOWN|GPM_DRAG)){
  1568.     if (event->x < 0 || event->x >= l->width)
  1569.         return MOU_REPEAT;
  1570.     if (event->y < 1)
  1571.         for (i = -event->y; i >= 0; i--)
  1572.         listbox_back (l);
  1573.     else if (event->y > l->height)
  1574.         for (i = event->y - l->height; i > 0; i--)
  1575.         listbox_fwd (l);
  1576.     else
  1577.         listbox_select_entry (l, listbox_select_pos (l, l->top,
  1578.                              event->y - 1));
  1579.     
  1580.     /* We need to refresh ourselves since the dialog manager doesn't */
  1581.     /* know about this event */
  1582.     listbox_callback (h, l, WIDGET_DRAW, 0);
  1583.     refresh ();
  1584.     return MOU_REPEAT;
  1585.     }
  1586.  
  1587.     /* Double click */
  1588.     if ((event->type & (GPM_DOUBLE|GPM_UP)) == (GPM_UP|GPM_DOUBLE)){
  1589.          if (event->x < 0 || event->x >= l->width)
  1590.              return MOU_NORMAL;
  1591.          if (event->y < 1 || event->y > l->height)
  1592.              return MOU_NORMAL;
  1593.     
  1594.     dlg_select_widget (l->widget.parent, l);
  1595.     listbox_select_entry (l, listbox_select_pos (l, l->top, event->y - 1)); 
  1596.  
  1597.     switch (l->action){
  1598.     case listbox_nothing:
  1599.         break;
  1600.  
  1601.     case listbox_finish:
  1602.         h->running   = 0;
  1603.         h->ret_value = B_ENTER;
  1604.         return MOU_ENDLOOP;
  1605.  
  1606.     case listbox_cback:
  1607.         if ((*l->cback)(l) == listbox_finish)
  1608.         return MOU_ENDLOOP;
  1609.     }
  1610.     }
  1611. #endif    
  1612.     return MOU_NORMAL;
  1613. }
  1614.  
  1615. static void listbox_destroy (WListbox *l)
  1616. {
  1617.     WLEntry *n, *p = l->list;
  1618.     int i;
  1619.  
  1620.     x_destroy_cmd (l);
  1621.     for (i = 0; i < l->count; i++){
  1622.     n = p->next;
  1623.     free (p->text);
  1624.     free (p);
  1625.     p = n;
  1626.     }
  1627. }
  1628.  
  1629. WListbox *listbox_new (int y, int x, int width, int height,
  1630.                int action, lcback callback)
  1631. {
  1632.     WListbox *l = xmalloc (sizeof (WListbox), "listbox_new");
  1633.     extern int slow_terminal;
  1634.     
  1635.     init_widget (&l->widget, y, x, height, width,
  1636.          (callback_fn)listbox_callback,
  1637.          (destroy_fn) listbox_destroy, (mouse_h)listbox_event);
  1638.  
  1639.     l->list   = l->top = l->current = 0;
  1640.     l->pos    = 0;
  1641.     l->width  = width;
  1642.     l->height = height;
  1643.     l->count  = 0;
  1644.     l->top    = 0;
  1645.     l->current= 0;
  1646.     l->cback  = callback;
  1647.     l->action = action;
  1648.     l->allow_duplicates = 1;
  1649.     l->scrollbar = slow_terminal ? 0 : 1;
  1650.     widget_want_hotkey (l->widget, 1);
  1651.     
  1652.     return l;
  1653. }
  1654.  
  1655. /* Listbox item adding function.  They still lack a lot of functionality */
  1656. /* any takers? */
  1657. static void listbox_append_item (WListbox *l, WLEntry *e)
  1658. {
  1659.     if (!l->list){
  1660.     l->list = e;
  1661.     l->top = e;
  1662.     l->current = e;
  1663.     e->next = l->list;
  1664.     e->prev = l->list;
  1665.     } else {
  1666.     e->next = l->list;
  1667.     e->prev = l->list->prev;
  1668.     l->list->prev->next = e;
  1669.     l->list->prev = e;
  1670.     }
  1671.     x_list_insert (l, l->list, e);
  1672.     l->count++;
  1673. }
  1674.  
  1675. char *listbox_add_item (WListbox *l, int pos, int hotkey, char *text,
  1676.             void *data)
  1677. {
  1678.     WLEntry *entry;
  1679.  
  1680.     if (!l)
  1681.     return 0;
  1682.  
  1683.     if (!l->allow_duplicates)
  1684.     if (listbox_search_text (l, text))
  1685.         return 0;
  1686.         
  1687.     entry = xmalloc (sizeof (WLEntry), "listbox_add_item");
  1688.     entry->text = strdup (text);
  1689.     entry->data = data;
  1690.     entry->hotkey = hotkey;
  1691.  
  1692.     listbox_append_item (l, entry);
  1693.     
  1694.     return entry->text;
  1695. }
  1696.  
  1697. /* Selects the nth entry in the listbox */
  1698. void listbox_select_by_number (WListbox *l, int n)
  1699. {
  1700.     listbox_select_entry (l, listbox_select_pos (l, l->list, n));
  1701. }
  1702.  
  1703. WLEntry *listbox_search_text (WListbox *l, char *text)
  1704. {
  1705.     WLEntry *e;
  1706.  
  1707.     e = l->list;
  1708.     if (!e)
  1709.     return NULL;
  1710.     
  1711.     do {
  1712.     if(!strcmp (e->text, text))
  1713.         return e;
  1714.     e = e->next;
  1715.     } while (e!=l->list);
  1716.  
  1717.     return NULL;
  1718. }
  1719.  
  1720. /* Returns the current string text as well as the associated extra data */
  1721. void listbox_get_current (WListbox *l, char **string, char **extra)
  1722. {
  1723.     if (!l->current){
  1724.     *string = 0;
  1725.     *extra  = 0;
  1726.     }
  1727.     if (string && l->current)
  1728.     *string = l->current->text;
  1729.     if (extra && l->current)
  1730.     *extra = l->current->data;
  1731. }
  1732.  
  1733. int buttonbar_callback (Dlg_head *h, WButtonBar *bb, int msg, int par)
  1734. {
  1735.     int i;
  1736.     
  1737.     switch (msg){
  1738.     case WIDGET_INIT:
  1739.     return x_create_buttonbar (h, h->wdata, bb);
  1740.  
  1741.     case WIDGET_FOCUS:
  1742.     return 0;
  1743.  
  1744.     case WIDGET_HOTKEY:
  1745.     for (i = 0; i < 10; i++){
  1746.         if (par == KEY_F(i+1) && bb->labels [i].function){
  1747.         (*bb->labels [i].function)(bb->labels [i].data);
  1748.         return 1;
  1749.         }
  1750.     }
  1751.     return 0;
  1752.     
  1753. #ifndef HAVE_X
  1754.     case WIDGET_DRAW:
  1755.     if (!bb->visible)
  1756.         return 1;
  1757.     widget_move (&bb->widget, 0, 0);
  1758.     attrset (DEFAULT_COLOR);
  1759.     printw ("%-*s", bb->widget.cols - 1, "");
  1760.     for (i = 0; i < COLS/8 && i < 10; i++){
  1761.         widget_move (&bb->widget, 0, i*8);
  1762.         attrset (DEFAULT_COLOR);
  1763.         printw ("%d", i+1);
  1764.         attrset (SELECTED_COLOR);
  1765.         printw ("%-*s", ((i+1) * 8 == COLS ? 5 : 6),
  1766.             bb->labels [i].text ? bb->labels [i].text : "");
  1767.         attrset (DEFAULT_COLOR);
  1768.     }
  1769.     attrset (SELECTED_COLOR);
  1770.     return 1;
  1771. #endif
  1772.     }
  1773.     return default_proc (h, msg, par);
  1774. }
  1775.  
  1776. static void buttonbar_destroy (WButtonBar *bb)
  1777. {
  1778.     int i;
  1779.  
  1780.     for (i = 0; i < 10; i++){
  1781.     if (bb->labels [i].text)
  1782.         free (bb->labels [i].text);
  1783.     }
  1784. }
  1785.  
  1786. static int buttonbar_event (Gpm_Event *event, WButtonBar *bb)
  1787. {
  1788. #ifndef HAVE_X
  1789.     int button;
  1790.  
  1791.     if (!(event->type & GPM_UP))
  1792.     return MOU_NORMAL;
  1793.     if (event->y == 2)
  1794.     return MOU_NORMAL;
  1795.     button = event->x / 8;
  1796.     if (button < 10 && bb->labels [button].function)
  1797.     (*bb->labels [button].function)(bb->labels [button].data);
  1798. #endif
  1799.     return MOU_NORMAL;
  1800. }
  1801.  
  1802. WButtonBar *buttonbar_new (int visible)
  1803. {
  1804.     int i;
  1805.     WButtonBar *bb = xmalloc (sizeof (WButtonBar), "buttonbar_new");
  1806.  
  1807.     init_widget (&bb->widget, LINES-1, 0, 1, COLS,
  1808.          (callback_fn) buttonbar_callback,
  1809.          (destroy_fn) buttonbar_destroy, (mouse_h) buttonbar_event);
  1810.     
  1811.     bb->visible = visible;
  1812.     for (i = 0; i < 10; i++){
  1813.     bb->labels [i].text     = 0;
  1814.     bb->labels [i].function = 0;
  1815.     }
  1816.     widget_want_hotkey (bb->widget, 1);
  1817.     widget_want_cursor (bb->widget, 0);
  1818.  
  1819.     return bb;
  1820. }
  1821.  
  1822. void set_label_text (WButtonBar *bb, int index, char *text)
  1823. {
  1824.     if (bb->labels [index-1].text)
  1825.     free (bb->labels [index-1].text);
  1826.  
  1827.     bb->labels [index-1].text = strdup (text);
  1828. }
  1829.  
  1830. /* paneletc is either the panel widget, or info or view or tree widget */
  1831. WButtonBar *find_buttonbar (Dlg_head *h, Widget *paneletc)
  1832. {
  1833.     WButtonBar *bb;
  1834.     Widget_Item *item;
  1835.     int i;
  1836.  
  1837.     bb = 0;
  1838.     for (i = 0, item = h->current; i < h->count; i++, item = item->next){
  1839.     if (item->widget->callback == (callback_fn) buttonbar_callback){
  1840.         bb = (WButtonBar *) item->widget;
  1841. #ifdef HAVE_XVIEW
  1842.         /* Jakub: do we really need this routine here?
  1843.          * Does XView hold more that a buttonbar per Dlg_head?
  1844.          */
  1845.         if (x_find_buttonbar_check (bb, paneletc)) {
  1846.             bb = 0;
  1847.             continue;
  1848.         }
  1849. #endif        
  1850.         break;
  1851.     }
  1852.     }
  1853.     return bb;
  1854. }
  1855. void define_label_data (Dlg_head *h, Widget *paneletc, int idx, char *text,
  1856.             buttonbarfn cback, void *data)
  1857. {
  1858.     WButtonBar *bb = find_buttonbar (h, paneletc);
  1859.     if (!bb)
  1860.     return;
  1861.     
  1862.     set_label_text (bb, idx, text);
  1863.     bb->labels [idx-1].function = (void (*)(void *)) cback;
  1864.     bb->labels [idx-1].data = data;
  1865.     x_redefine_label (bb, idx);
  1866. }
  1867.  
  1868. void define_label (Dlg_head *h, Widget *paneletc, 
  1869.     int idx, char *text, void (*cback)(void))
  1870. {
  1871.     define_label_data (h, paneletc, idx, text, (void (*)(void *)) cback, 0);
  1872. }
  1873.  
  1874. void redraw_labels (Dlg_head *h, Widget *paneletc)
  1875. {
  1876. #ifndef HAVE_X
  1877.     Widget_Item *item;
  1878.     int i;
  1879.  
  1880.     for (i = 0, item = h->current; i < h->count; i++, item = item->next){
  1881.     if (item->widget->callback == (callback_fn) buttonbar_callback){
  1882.         widget_redraw (h, item);
  1883.         return;
  1884.     }
  1885.     }
  1886. #endif
  1887. }
  1888.  
  1889.  
  1890.  
  1891.